package org.example.sentinel.controller;

import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.example.sentinel.config.SentinelExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * @author tds
 * @version 1.0.0
 * @Company
 * @ClassName SentinelDemoController
 * @Description TODO（这里用一句话描述这个类的作用)
 * @Date 2023-04-22 15:11
 */
@RestController
public class SentinelDemoController {

    /**
     * 我们说的资源，可以是任何东西，服务，服务里的方法，甚至是一段代码。使用 Sentinel 来进行资源保护，主要分为几个步骤:
     *  - 定义资源
     *  - 定义规则
     *  - 检验规则是否生效
     */
    private static final String RESOURCE = "Hello";

    @PostConstruct
    public void init() {
        // 注：同一个资源可以同时有多个限流规则。
        // Sentinel 支持以下几种规则：流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则 和 热点参数规则。

        // ==================== 1.流量控制规则 ==================
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        // 资源名，资源名是限流规则的作用对象
        rule.setResource(RESOURCE);
        // 限流阈值
        rule.setCount(1);
        // 限流阈值类型，QPS 或线程数模式
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//        rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);
        // 流控针对的调用来源。default，代表不区分调用来源
        rule.setLimitApp("default");
//        rule.setMaxQueueingTimeMs(5000);
        // 调用关系限流策略：直接、链路、关联
//        rule.setStrategy(RuleConstant.STRATEGY_DIRECT);
        // 流控效果（直接拒绝 / 排队等待 / 慢启动模式），不支持按调用关系限流
        rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
//        rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

    @RequestMapping("test")
    public String test() {
        // ============ 1、抛出异常方式定义资源 ============
        Entry entry = null;
        try {
            entry = SphU.entry(RESOURCE);
            // 被保护的业务逻辑
            System.out.println("Hello World!");
//            ThreadUtil.sleep(2000);
        } catch (BlockException e) {
            // 资源访问阻止，被限流或被降级进行相应的处理操作
            System.out.println("setinel拒绝请求：" + e.getRule());
            e.printStackTrace();
            return "限流了";
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
        return "test";
    }

    @SentinelResource(
            value = RESOURCE,
            fallback = "fallbackMethod",
            fallbackClass = SentinelExceptionHandler.class,
            blockHandler = "blockHandler",
            blockHandlerClass = SentinelExceptionHandler.class
    )
    @RequestMapping("test2")
    public String test2() {
        // ============ 1、注解方式定义资源 ============
        // 通过 @SentinelResource 注解定义资源并配置 blockHandler 和 fallback 函数来进行限流之后的处理
        // 注意 blockHandler 函数会在原方法被限流/降级/系统保护的时候调用，而 fallback 函数会针对所有类型的异常。请注意 blockHandler 和
        // fallback 函数的形式要求，更多指引可以参见 Sentinel 注解支持文档:https://sentinelguard.io/zh-cn/docs/annotation-support.html
        // 被保护的业务逻辑
        throw new RuntimeException("123");
//        System.out.println("Hello World!");
//        ThreadUtil.sleep(2000);
//        return "test2";
    }

//    public String fallbackMethod(Throwable ex) {
//        ex.printStackTrace();
//        System.out.println("errormessage:" + ex.getMessage());
//        return "fallback";
//    }
//
//    public String blockHandler(BlockException blockException) {
//        System.out.println("blockHandler:" + blockException.getRule());
//        return "blockHandler";
//    }
}
